#ifndef PARSE_EXPRESSION_H__
#define PARSE_EXPRESSION_H__

#include <stdlib.h>
#include "token.h"
#include "parse-type.h"
#include "../ast/expression.h"

#if 0
import std.lib;
import token;
import parse-type;
import ..ast.expression;
#endif

struct Expression* parseSimpleExpression(struct TokenList**);
struct Expression* parsePotentialCastExpression(struct TokenList**);
struct Expression* parseExpression(struct TokenList**);

struct Expression* parseSimpleExpression(struct TokenList** source)
{
	if(*source == NULL) return NULL;

	struct TokenList* save = *source;
	struct Expression* r = NULL;

	if((*source)->head->tag == CHARACTER_LITERAL_TOKEN)
		r = allocateExpression(CHARACTER_LITERAL_EXPRESSION,
			parseCharacterLiteral(source),NULL);

	else if((*source)->head->tag == INTEGER_LITERAL_TOKEN)
		r = allocateExpression(INTEGER_LITERAL_EXPRESSION,
			parseIntegerLiteral(source),NULL);

	else if((*source)->head->tag == NAME_TOKEN)
		r = allocateExpression(NAME_EXPRESSION,parseName(source),NULL);

	else if((*source)->head->tag == STRING_LITERAL_TOKEN)
		r = allocateExpression(STRING_LITERAL_EXPRESSION,
			parseStringLiteral(source),NULL);

	else if((*source)->head->tag == OPEN_BRACKET)
	{
		*source = (*source)->tail;
		r = allocateExpression(BRACKET_EXPRESSION,NULL,
			parseExpression(source));

		if(r->right != NULL && (*source)->head->tag == CLOSE_BRACKET)
			*source = (*source)->tail;

		else
		{
			*source = save;
			freeExpression(r);
			r = NULL;
		}
	}

	else if((*source)->head->tag == OPEN_PARENTHESE)
	{
		*source = (*source)->tail;
		r = allocateExpression(PARENTHESE_EXPRESSION,NULL,
			parseExpression(source));

		if(r->right != NULL && (*source)->head->tag == CLOSE_PARENTHESE)
			*source = (*source)->tail;

		else
		{
			*source = save;
			freeExpression(r);
			r = NULL;
		}
	}

	else if((*source)->head->tag == AT || (*source)->head->tag == STAR)
	{
		*source = (*source)->tail;
		r = allocateExpression(DEREFERENCE_EXPRESSION,
			parseSimpleExpression(source),NULL);
	}

	else if((*source)->head->tag == AMPERSAND)
	{
		*source = (*source)->tail;
		r = allocateExpression(LOCATION_EXPRESSION,
			parseSimpleExpression(source),NULL);
	}

	else if((*source)->head->tag == DASH)
	{
		*source = (*source)->tail;
		r = allocateExpression(NEGATION_EXPRESSION,
			parseSimpleExpression(source),NULL);
	}

	else if((*source)->head->tag == PLUS)
	{
		*source = (*source)->tail;
		r = allocateExpression(POSITIVISATION_EXPRESSION,
			parseSimpleExpression(source),NULL);
	}

	else if((*source)->head->tag == EXCLAMATION_POINT)
	{
		*source = (*source)->tail;
		r = allocateExpression(NOT_EXPRESSION,
			parseSimpleExpression(source),NULL);
	}

	else if((*source)->head->tag == TILDE)
	{
		*source = (*source)->tail;
		r = allocateExpression(BITWISE_COMPLEMENT_EXPRESSION,
			parseSimpleExpression(source),NULL);
	}

	// The following removes left-recursion

	struct Expression* left = r;

	while(*source != NULL
		&& ((*source)->head->tag == OPEN_BRACKET
			|| (*source)->head->tag == OPEN_PARENTHESE))
	{
		r = left;
		struct TokenList* save = *source;
		*source = (*source)->tail;

		if(*source != NULL && save->head->tag == OPEN_BRACKET)
		{
			left = allocateExpression(BRACKET_EXPRESSION,left,
				parseExpression(source));

			if(*source != NULL && (*source)->head->tag == CLOSE_BRACKET)
				*source = (*source)->tail;

			else
			{
				*source = save;
				freeExpression(left);
				return r;
			}
		}

		else
		{
			left = allocateExpression(PARENTHESE_EXPRESSION,left,
				parseExpression(source));

			if(*source != NULL && (*source)->head->tag == CLOSE_PARENTHESE)
				*source = (*source)->tail;

			else
			{
				*source = save;
				freeExpression(left);
				return r;
			}
		}
	}

	return r;
}

struct Expression* parsePotentialCastExpression(struct TokenList** source)
{
	if(*source != NULL && (*source)->head->tag == OPEN_PARENTHESE)
	{
		struct TokenList* save = *source;
		*source = (*source)->tail;
		struct Expression* r = allocateExpression(CAST_EXPRESSION,
			parseType(source),NULL);

		if(*source != NULL
			&& r->left != NULL
			&& (*source)->head->tag == CLOSE_PARENTHESE)
		{
			*source = (*source)->tail;
			r->right = parseSimpleExpression(source);

			if(r->right != NULL)
				return r;
		}

		*source = save;
	}

	return parseSimpleExpression(source);
}

struct Expression* parseExpression(struct TokenList** source)
{
	// Add support for infix expressions.
	return parsePotentialCastExpression(source);
}

#endif

